package com.hsh.gaoqianlianmeng.aspect;


import com.hsh.gaoqianlianmeng.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Objects;

@Aspect
@Component
@Slf4j
public class RequestAspect {

    @Resource
    private JsonUtils jsonUtils;

    /**
     * 声明切点，后续使用时直接使用 controllerMethod() 即可
     * 等价于不声明直接使用  @Around( pointcut="execution( * com.hsh.gaoqianlianmeng.controller..*.*(..))")
     */
    @Pointcut("execution(* com.hsh.gaoqianlianmeng.controller..*.*(..))")
    public void controllerMethod() {
    }

    /**
     * 环绕通知
     * 输出 url，参数，返回等内容
     *
     * @param proceedingJoinPoint 环绕所需切点
     * @return
     * @throws Throwable
     */
    @Around("controllerMethod()")
    public Object aroundController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        StringBuilder logInfo = new StringBuilder();
        logInfo.append(":\n");
        logInfo.append("========================================= Start ==========================================\n");
        //获得request
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        //请求开始时间
        logInfo.append("-- start time   : ").append(LocalDateTime.now()).append("\n");
        //记录请求url
        logInfo.append("-- path         : ").append(request.getRequestURL()).append("\n");
        //请求类型
        logInfo.append("-- method       : ").append(request.getMethod()).append("\n");
        //参数
        logInfo.append("-- params       : ").append(getParams(proceedingJoinPoint)).append("\n");
        Object result;
        try {
            //对原始操作的调用
            result = proceedingJoinPoint.proceed();
        } catch (Exception e) {
            //异常时，将异常消息作为返回值打印出来，
            //也可以自定义response，设置返回码200，将异常作为成功访问返回前端
            StringBuilder exceptionStr = new StringBuilder();
            exceptionStr.append(e.getMessage());
            for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                exceptionStr.append(stackTraceElement.toString()).append("\n");
            }
            System.out.println(exceptionStr);
            result = exceptionStr;
        }
        //返回结果
        logInfo.append("-- result       : ").append(jsonUtils.toJson(result)).append("\n");
        //请求结束时间
        logInfo.append("-- end time     : ").append(LocalDateTime.now()).append("\n");
        logInfo.append("========================================== End ===========================================\n");
        log.info(logInfo.toString());
        return result;
    }


    /**
     * 获取切点的参数
     *
     * @param joinPoint
     * @return Json格式的字符串
     */
    private String getParams(ProceedingJoinPoint joinPoint) {
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        CodeSignature signature = (CodeSignature) joinPoint.getSignature();
        String[] names = signature.getParameterNames();
        Object[] value = joinPoint.getArgs();
        for (int i = 0; i < names.length; i++) {
            map.put(names[i], value[i]);
        }
        return jsonUtils.toJson(map);
    }
}
